<template>
  <view>
    <view
      v-if="list && list.length > 0"
      :style="{ height: height + 'rpx', width: width ? width + 'rpx' : '100%' }"
      class="swiper-container"
      @touchstart="touchStart"
      @touchend="touchEnd"
    >
      <view
        class="swiper-item"
        v-for="(item, index) in list"
        :key="index"
        :style="{
          transform: styleList[index].transform,
          'z-index': styleList[index].zIndex,
          opacity: styleList[index].opacity,
          display: styleList[index].display
        }"
      >
        <view
          @click="itemClick(item.pageUrl)"
          class="wrap"
          :style="{ width: showNum == 5 && list.length >= 5 ? '84%' : '90%' }"
        >
          <image class="image" :src="isObj(item) ? item.imgUrl : item" />
          <!-- <view
            v-if="isObj(item) && item.imgDesc"
            :class="['image-desc', descAniType, { curr: curr == index }]"
            >{{ item.imgDesc }}
          </view> -->
        </view>
      </view>
    </view>
    <view class="sw-con" v-if="showDot">
      <view class="t-dot-con">
        <view
          class="t-dot-active"
          :style="{ left: 32 * curr + curr * 8 + 'rpx', background: dotSelectedColor }"
        />
        <block v-for="(dot, idx) in list.length" :key="idx">
          <view class="t-dot-wrap">
            <view :class="['t-dot', { active: idx == curr }]" :style="{ background: dotColor }" />
          </view>
        </block>
      </view>
    </view>
  </view>
</template>

<script>
export default {
  props: {
    /**calc(100% - )
     * 图片url列表，内部结构为Object，示例{"imgUrl":"http://www.abc.com/a.jpg","imgDesc":"我是描述文字"}
     */
    list: {
      type: Array,
      default: () => []
    },
    /**
     * swiper高度--单位rpx
     */
    height: {
      type: Number,
      default: 690
    },
    /**
     * 显示图片个数，仅支持3或5，默认3
     */
    showNum: {
      type: Number,
      default: 3
    },
    /**
     * swiper宽度--单位rpx
     */
    width: {
      type: Number,
      default: undefined
    },
    /**
     * 是否自动播放
     */
    autoPlay: {
      type: Boolean,
      default: false
    },
    /**
     * 自动播放间隔毫秒
     */
    autoPlayInterval: {
      type: Number,
      default: 5000
    },
    /**
     * 是否显示轮播指示点
     */
    showDot: {
      type: Boolean,
      default: false
    },
    /**
     * 图片描述文字动画类型：slideFromRight、slideFromBottom、scaleX、scaleY
     */
    descAniType: {
      type: String,
      default: 'slideFromRight'
    },
    /**
     * 指示点未选中背景色，支持css颜色值及渐变
     */
    dotColor: {
      type: String,
      default: 'linear-gradient(to bottom, #999999, #c0c0c0)'
    },
    /**
     * 指示点选中背景色，支持css颜色值及渐变
     */
    dotSelectedColor: {
      type: String,
      default: 'linear-gradient(to bottom, #92ffc0, #002661)'
    }
  },
  data() {
    return {
      curr: 0,
      /**
       * 开始触摸点坐标
       */
      start: {
        x: 0,
        y: 0
      },
      /**
       * 每个item样式列表
       */
      styleList: [],
      timer: undefined
    }
  },
  created() {
    this.isObj({})
    this.initSwiper()
  },
  watch: {
    list(newVal, oldVal) {
      this.curr = 0
      this.start = {
        x: 0,
        y: 0
      }
      this.styleList = []
      this.closeTimer()
      this.initSwiper()
    }
  },
  methods: {
    //初始化swiper
    initSwiper() {
      if (this.list && this.list.length > 0) {
        this.list.forEach((item, index) => {
          this.styleList.push(this.addStyle(index))
        })
        this.openTimer()
      }
    },

    //开启自动定时器
    openTimer() {
      if (this.autoPlay === true && this.list.length > 1 && !this.timer) {
        this.timer = setInterval(() => {
          this.curr = this.curr == this.list.length - 1 ? 0 : this.curr + 1
          this.toSlideLeft()
        }, this.autoPlayInterval)
      }
    },
    //关闭自动定时器
    closeTimer() {
      if (this.autoPlay === true && this.list.length > 1) {
        clearInterval(this.timer)
        this.timer = undefined
      }
    },
    /**
     * 计算每个item样式
     * @param {Object} idx
     */
    addStyle(idx) {
      const len = this.list.length
      const sn = this.showNum == 5 && this.list.length >= 5 ? 2 : 1
      if (idx > len / 2) {
        //这里是数组后一半的item放在左边,平移位置由远到近，例如共6个，后2个处理在这里
        var left = len - idx
        return {
          transform: 'scale(' + (1 - left / 10) + ') translate(-' + left * 11 + '%,0px)',
          zIndex: 9999 - left,
          //   opacity: 0.8 / left,
          display: idx >= len - sn ? 'block' : 'none'
        }
      } else {
        //这里是数组前一半item放在右边，平移位置由近到远，例如共6个，前4个处理在这里，这里第一个元素始终放在中间位置
        return {
          transform: 'scale(' + (1 - idx / 10) + ') translate(' + idx * 11 + '%,0px)',
          zIndex: 9999 - idx,
          //   opacity: 0.8 / (idx === 0 ? 0.8 : idx),
          display: idx > sn ? 'none' : 'block'
        }
      }
    },
    /**
     * 触摸开始
     * @param {Object} e
     */
    touchStart(e) {
      this.start.x = e.changedTouches[0] ? e.changedTouches[0].pageX : 0
      this.start.y = e.changedTouches[0] ? e.changedTouches[0].pageY : 0
      this.closeTimer()
    },
    /**
     * 触摸结束
     * @param {Object} e
     */
    touchEnd(e) {
      this.openTimer()
      const len = this.styleList.length
      const tx = e.changedTouches[0].pageX - this.start.x
      const ty = e.changedTouches[0].pageY - this.start.y
      if (Math.abs(tx) > Math.abs(ty)) {
        //左右方向滑动
        if (tx === 0) {
          //点击事件拦截
          return
        }
        if (tx < 0) {
          // 向左滑动--手指向左滑动
          this.curr = this.curr === len - 1 ? 0 : this.curr + 1
          this.toSlideLeft()
        } else if (tx > 0) {
          // 向右滑动--手指向右滑动
          this.curr = this.curr === 0 ? len - 1 : this.curr - 1
          this.toSlideRight()
        }
      } else {
        //这里就不处理上下方向的事件了，有此需求的同仁可以在这里写逻辑
        //上下方向滑动
        if (tx === 0) {
          //点击事件拦截
          return
        }
        if (ty < 0) {
          // 向上滑动
        } else if (ty > 0) {
          // 向下滑动
        }
      }
    },
    // 向左滑动--手指向左滑动
    toSlideLeft() {
      var newStyleList = JSON.parse(JSON.stringify(this.styleList))
      var last = [newStyleList.pop()]
      newStyleList = last.concat(newStyleList)
      this.styleList = newStyleList
      //触发change事件
      this.$emit('change', this.curr)
    },
    // 向右滑动--手指向右滑动
    toSlideRight() {
      var newStyleList = JSON.parse(JSON.stringify(this.styleList))
      var first = [newStyleList.shift()]
      newStyleList = newStyleList.concat(first)
      this.styleList = newStyleList
      //触发change事件
      this.$emit('change', this.curr)
    },
    /**
     * 当前item点击返回索引下标
     * @param {Object} idx
     */
    itemClick(idx) {
      uni.redirectTo({
        url: idx
      })
    },
    //是否为对象
    isObj(o) {
      try {
        return typeof o === 'object' && o !== null
      } catch (e) {
        return false
      }
    }
  }
}
</script>

<style lang="scss" scoped>
.swiper-container {
  position: relative;
  box-sizing: border-box;
  width: 100%;
  height: 690rpx;
  overflow: hidden;

  .swiper-item {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    transition: all 0.5s;

    //需要缩放动画的话注释下方放开这个
    .wrap {
      position: relative;
      width: 90%;
      height: 100%;
      margin: 2rpx auto;
      overflow: hidden;

      .image {
        width: 100%;
        height: 100%;
        border-radius: 12rpx;
        // box-shadow: 0 0 10rpx #333;//加阴影的话去掉注释即可
      }

      .image-desc {
        position: absolute;
        bottom: 0rpx;
        box-sizing: border-box;
        width: 100%;
        height: 60rpx;
        padding: 0rpx 20rpx;
        overflow: hidden;
        font-size: 30rpx;
        line-height: 60rpx;
        color: #fff;
        text-align: left;
        text-overflow: ellipsis;
        white-space: nowrap;
        background: rgb(0 0 0 / 30%);
        border-radius: 0rpx 0rpx 10rpx 10rpx;
        opacity: 0;
        transition: all 1s ease-out;

        //动画类型slideFromRight
        &.slideFromRight {
          transform: translateX(100%);

          &.curr {
            opacity: 1;
            transform: translateX(0);
          }
        }

        //动画类型slideFromBottom
        &.slideFromBottom {
          transform: translateY(100%);

          &.curr {
            opacity: 1;
            transform: translateY(0);
          }
        }

        //动画类型scaleX
        &.scaleX {
          transform: scaleX(0);

          &.curr {
            opacity: 1;
            transform: scaleX(1);
          }
        }

        //动画类型scaleX
        &.scaleY {
          transform: scaleY(0);

          &.curr {
            opacity: 1;
            transform: scaleY(1);
          }
        }
      }
    }
  }
}

.sw-con {
  position: relative;
  box-sizing: border-box;
  display: flex;
  flex-direction: row;
  align-items: center;
  justify-content: center;
  width: 100%;
  margin-top: 26rpx;

  .t-dot-con {
    position: relative;
    box-sizing: border-box;
    display: inline-block;
  }

  .t-dot-wrap {
    display: flex;
    flex-direction: row;
    align-items: center;
    justify-content: center;
    float: left;
    width: 32rpx;
    height: 8rpx;
    margin-right: 8rpx;
    border-radius: 4rpx;
  }

  .t-dot {
    float: left;
    width: 32rpx;
    height: 8rpx;
    // background: linear-gradient(to bottom, #666666, #999999);
    // background: -webkit-linear-gradient(to bottom, #666666, #999999);
    // opacity: 0.3;
    transition: all 200ms ease-out;

    &.active {
      background: rgb(0 0 0 / 0%) !important;
    }
  }

  .t-dot-active {
    position: absolute;
    top: 0rpx;
    left: 0rpx;
    z-index: 1;
    width: 32rpx;
    height: 8rpx;
    border-radius: 4rpx;
    transition: all 0.3s ease-in-out;
    // background: linear-gradient(to bottom, #92ffc0, #002661);
    // background: -webkit-linear-gradient(to bottom, #92ffc0, #002661);
  }
}
</style>
